﻿using Notepad_Clone.FindReplace;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace Notepad_Clone
{
    partial class NotepadClone : Window
    {
        string strFindWhat = string.Empty, strReplaceWith = string.Empty;
        StringComparison strcomp = StringComparison.OrdinalIgnoreCase;
        Direction dirFind = Direction.Down;

        void AddFindMenuItems(MenuItem itemEdit)
        {
            MenuItem itemFind = new MenuItem();
            itemFind.Header = "_Find...";
            itemFind.Command = ApplicationCommands.Find;
            itemEdit.Items.Add(itemFind);
            this.CommandBindings.Add(new CommandBinding(ApplicationCommands.Find, this.FindOnExecute, this.FindCanExecute));

            InputGestureCollection coll = new InputGestureCollection();
            coll.Add(new KeyGesture(Key.F3));
            RoutedUICommand commFindNext = new RoutedUICommand("Find _Next", "FindNext", this.GetType(), coll);

            MenuItem itemNext = new MenuItem();
            itemNext.Command = commFindNext;
            itemEdit.Items.Add(itemNext);
            this.CommandBindings.Add(new CommandBinding(commFindNext, this.FindNextOnExecute, this.FindNextCanExecute));

            MenuItem itemReplace = new MenuItem();
            itemReplace.Header = "_Replace...";
            itemReplace.Command = ApplicationCommands.Replace;
            itemEdit.Items.Add(itemReplace);
            this.CommandBindings.Add(new CommandBinding(ApplicationCommands.Replace, this.ReplaceOnExecute, this.FindCanExecute));
        }

        private void ReplaceOnExecute(object sender, ExecutedRoutedEventArgs e)
        {
            ReplaceDialog dlg = new ReplaceDialog(this);
            dlg.FindWhat = this.strFindWhat;
            dlg.ReplaceWith = this.strReplaceWith;
            dlg.MatchCase = this.strcomp == StringComparison.Ordinal;
            dlg.Direction = this.dirFind;
            dlg.FindNext += this.FindDialogOnFindNext;
            dlg.Replace += this.ReplaceDialogOnReplace;
            dlg.ReplaceAll += this.ReplaceDialogOnReplaceAll;
            dlg.Show();
        }

        private void ReplaceDialogOnReplaceAll(object sender, EventArgs e)
        {
            ReplaceDialog dlg = sender as ReplaceDialog;
            string str = this.txtbox.Text;
            this.strFindWhat = dlg.FindWhat;
            this.strReplaceWith = dlg.ReplaceWith;
            this.strcomp = dlg.MatchCase ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase;
            int index = 0;
            while (index + this.strFindWhat.Length < str.Length)
            {
                index = str.IndexOf(this.strFindWhat, index, this.strcomp);
                if (index != -1)
                {
                    str = str.Remove(index, this.strFindWhat.Length);
                    str = str.Insert(index, this.strReplaceWith);
                    index += this.strReplaceWith.Length;
                }
                else
                {
                    break;
                }
            }

            this.txtbox.Text = str;
        }

        private void ReplaceDialogOnReplace(object sender, EventArgs e)
        {
            ReplaceDialog dlg = sender as ReplaceDialog;
            this.strFindWhat = dlg.FindWhat;
            this.strReplaceWith = dlg.ReplaceWith;
            this.strcomp = dlg.MatchCase ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase;
            if (this.strFindWhat.Equals(this.txtbox.SelectedText, this.strcomp))
            {
                this.txtbox.SelectedText = this.strReplaceWith;
            }

            this.FindNext();

        }

        private void FindNextOnExecute(object sender, ExecutedRoutedEventArgs e)
        {
            if (this.strFindWhat == null || this.strFindWhat.Length == 0)
            {
                this.FindOnExecute(sender, e);
            }
            else
            {
                this.FindNext();
            }
        }

        private void FindNext()
        {
            int indexStart, indexFind;
            if (this.dirFind == Direction.Down)
            {
                indexStart = this.txtbox.SelectionStart + this.txtbox.SelectionLength;
                indexFind = this.txtbox.Text.IndexOf(this.strFindWhat, indexStart, this.strcomp);
            }
            else
            {
                indexStart = this.txtbox.SelectionStart;
                indexFind = this.txtbox.Text.LastIndexOf(this.strFindWhat, indexStart, this.strcomp);
            }

            if (indexFind != -1)
            {
                this.txtbox.Select(indexFind, this.strFindWhat.Length);
                this.txtbox.Focus();
            }
            else
            {
                MessageBox.Show(
                    "Cannot find \"" + this.strFindWhat + "\"",
                    this.Title,
                    MessageBoxButton.OK,
                    MessageBoxImage.Information);
            }
        }

        private void FindNextCanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = (this.txtbox.Text.Length > 0 && this.strFindWhat.Length > 0);
        }

        private void FindCanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = (this.txtbox.Text.Length > 0 && this.OwnedWindows.Count == 0);
        }

        private void FindOnExecute(object sender, ExecutedRoutedEventArgs e)
        {
            FindDialog dlg = new FindDialog(this);
            dlg.FindWhat = this.strFindWhat;
            dlg.MatchCase = this.strcomp == StringComparison.Ordinal;
            dlg.Direction = this.dirFind;
            dlg.FindNext += this.FindDialogOnFindNext;
            dlg.Show();
        }

        private void FindDialogOnFindNext(object sender, EventArgs e)
        {
            FindReplaceDialog dlg = sender as FindReplaceDialog;
            this.strFindWhat = dlg.FindWhat;
            this.strcomp = dlg.MatchCase ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase;
            this.dirFind = dlg.Direction;
            this.FindNext();
        }
    }
}
